/*
 * MathML.java
 *
 * Created on June 3, 2005, 1:53 PM
 *
 * (C) R. Alexander Milowski alex@milowski.com
 */

package com.milowski.monos;

import java.net.*;
import java.util.*;
import java.util.regex.*;
import com.milowski.monos.monomial.*;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;

/**
 *
 * @author R. Alexander Milowski
 */
public class MathML {

   public static final URI MATHML = InfosetFactory.createNamespace("http://www.w3.org/1998/Math/MathML");

   // MathML
   public static final Name MathML_mathName = InfosetFactory.createName(MATHML,"math");
   public static final Name MathML_moName = InfosetFactory.createName(MATHML,"mo");
   public static final Name MathML_miName = InfosetFactory.createName(MATHML,"mi");
   public static final Name MathML_msupName = InfosetFactory.createName(MATHML,"msup");
   public static final Name MathML_msubName = InfosetFactory.createName(MATHML,"msub");
   public static final Name MathML_msubsupName = InfosetFactory.createName(MATHML,"msubsup");
   public static final Name MathML_mnName = InfosetFactory.createName(MATHML,"mi");
   public static final Name MathML_mrowName = InfosetFactory.createName(MATHML,"mrow");
   public static final Name MathML_mfencedName = InfosetFactory.createName(MATHML,"mfenced");

   ItemConstructor constructor;
   ItemDestination dest;

    /** Creates a new instance of MathML */
   public MathML(ItemConstructor constructor,ItemDestination dest) {
      this.constructor = constructor;
      this.dest = dest;
   }

   public void outputIntersection(LexOrderedList components)
      throws XMLException
   {
      outputIntersection(constructor,dest,components);
   }

   public static void outputIntersection(ItemConstructor constructor,ItemDestination dest,LexOrderedList components) 
      throws XMLException
   {
      List translatedLexOrder = translateLexOrder(components.getLexOrder());
      for (Iterator toOutput=components.iterator(); toOutput.hasNext(); ) {
         LexOrderedList component = (LexOrderedList)toOutput.next();
         outputGenerator(constructor,dest,translatedLexOrder,component);
         if (toOutput.hasNext()) {
            dest.send(constructor.createElement(MathML_moName));
            dest.send(constructor.createCharacters("\u2229"));
            dest.send(constructor.createElementEnd(MathML_moName));
         }
      }
   }
   
   public void outputGenerator(LexOrderedList generator)
      throws XMLException
   {
      outputGenerator(constructor,dest,translateLexOrder(generator.getLexOrder()),generator);
   }

   public static void outputGenerator(ItemConstructor constructor,ItemDestination dest,List lexOrder,LexOrderedList component) 
      throws XMLException
   {
      Element fenced = constructor.createElement(MathML_mfencedName);
      fenced.setAttributeValue("open","<");
      fenced.setAttributeValue("close",">");
      dest.send(fenced);
      for (Iterator toOutput=component.iterator(); toOutput.hasNext(); ) {
         Monomial monomial = (Monomial)toOutput.next();
         outputMonomial(constructor,dest,lexOrder,monomial);
      }
      dest.send(constructor.createElementEnd(MathML_mfencedName));
   }
   
   public static List translateLexOrder(LexOrder order) {
      Pattern p = Pattern.compile("^(\\D+)(\\d*)");
      List result = new ArrayList();
      for (Iterator toConvert=order.iterator(); toConvert.hasNext(); ) {
         String var = (String)toConvert.next();
         //System.err.println("Matching '"+var+"'");
         Matcher matcher = p.matcher(var);
         if (matcher.matches()) {
            String prefix = matcher.group(1);
            String index = matcher.group(2);
            //System.err.println("Matched: "+prefix+" "+index);
            if (index==null || index.length()==0) {
               result.add(var);
            } else {
               String [] varSpec = { prefix, index };
               result.add(varSpec);
            }
         } else {
            result.add(var);
         }
      }
      return result;
   }
   
   public void outputMonomial(List order,Monomial monomial)
      throws XMLException
   {
      outputMonomial(constructor,dest,order,monomial);
   }

   public static void outputMonomial(ItemConstructor constructor,ItemDestination dest,List order,Monomial monomial) 
      throws XMLException
   {
      dest.send(constructor.createElement(MathML_mrowName));
      short [] values = monomial.getValues();
      int lastNonZero = -1;
      for (int i=0; i<values.length; i++) {
         Object varObject = order.get(i);
         if (varObject instanceof String) {
            String var = (String)varObject;
            if (values[i]==1) {
               dest.send(constructor.createElement(MathML_miName));
                  dest.send(constructor.createCharacters(var));
               dest.send(constructor.createElementEnd(MathML_miName));
            } else if (values[i]!=0) {
               dest.send(constructor.createElement(MathML_msupName));
                  dest.send(constructor.createElement(MathML_miName));
                     dest.send(constructor.createCharacters(var));
                  dest.send(constructor.createElementEnd(MathML_miName));
                  dest.send(constructor.createElement(MathML_mnName));
                     dest.send(constructor.createCharacters(Short.toString(values[i])));
                  dest.send(constructor.createElementEnd(MathML_mnName));
               dest.send(constructor.createElementEnd(MathML_msupName));
            }
         } else {
            String [] var = (String [])varObject;
            if (values[i]==1) {
               dest.send(constructor.createElement(MathML_msubName));
                  dest.send(constructor.createElement(MathML_miName));
                     dest.send(constructor.createCharacters(var[0]));
                  dest.send(constructor.createElementEnd(MathML_miName));
                  dest.send(constructor.createElement(MathML_mnName));
                     dest.send(constructor.createCharacters(var[1]));
                  dest.send(constructor.createElementEnd(MathML_mnName));
               dest.send(constructor.createElementEnd(MathML_msubName));
            } else if (values[i]!=0) {
               dest.send(constructor.createElement(MathML_msubsupName));
                  dest.send(constructor.createElement(MathML_miName));
                     dest.send(constructor.createCharacters(var[0]));
                  dest.send(constructor.createElementEnd(MathML_miName));
                  dest.send(constructor.createElement(MathML_mnName));
                     dest.send(constructor.createCharacters(var[1]));
                  dest.send(constructor.createElementEnd(MathML_mnName));
                  dest.send(constructor.createElement(MathML_mnName));
                     dest.send(constructor.createCharacters(Short.toString(values[i])));
                  dest.send(constructor.createElementEnd(MathML_mnName));
               dest.send(constructor.createElementEnd(MathML_msubsupName));
            }
            
         }
      }
      dest.send(constructor.createElementEnd(MathML_mrowName));
   }

}
